package com.xinchuang.utils;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpStatus;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xinchuang.entity.image.ImageGrid;
import lombok.extern.slf4j.Slf4j;

import javax.json.JsonArray;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * TODO
 *
 * @author zkwczx
 * @version 1.0
 * @date 2023/11/28 20:40
 */
@Slf4j
public class RunExeUtil {

    // 地球的平均半径（米）
    private static final double EARTH_RADIUS = 6371000;

    // 计算两点之间的距离（米）
    private static double distance(double lat1, double lon1, double lat2, double lon2) {
        double dLat = Math.toRadians(lat2 - lat1);
        double dLon = Math.toRadians(lon2 - lon1);
        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
                Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
                        Math.sin(dLon / 2) * Math.sin(dLon / 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        return EARTH_RADIUS * c;
    }

    // 计算圆形的中心点经纬度坐标
    private static JSONObject calculateCircleCenter(double lat, double lon, double radius, double angle, double isRound) {
        // angular distance in radians
        double d = radius / EARTH_RADIUS;
        double lat1 = Math.toRadians(lat);
        double lon1 = Math.toRadians(lon);

        double lat2 = Math.asin(Math.sin(lat1) * Math.cos(d) +
                Math.cos(lat1) * Math.sin(d) * Math.cos(angle));
        double lon2 = lon1 + Math.atan2(Math.sin(angle) * Math.sin(d) * Math.cos(lat1),
                Math.cos(d) - Math.sin(lat1) * Math.sin(lat2));
        return getJsons("round", Math.toDegrees(lon2), Math.toDegrees(lat2), isRound);
    }

    public static JSONObject getJsons(String type, double lon, double lat, double isRound) {
        JSONObject jsons = new JSONObject();
        jsons.put("id", UUID.randomUUID().toString());
        jsons.put("type", MyUtil.toWeb(type));
        jsons.put("json", Arrays.asList(lon, lat, 0.0));
        jsons.put("radius", isRound);
        return jsons;
    }

    public static JSONObject getJsons(String type, JSONArray position) {
        JSONObject jsons = new JSONObject();
        jsons.put("id", UUID.randomUUID().toString());
        jsons.put("type", MyUtil.toWeb(type));
        jsons.put("json", position);
        return jsons;
    }

    // 计算大圆的周长
    public static double calculateCircumference(double radius) {
        return 2 * Math.PI * radius;
    }

    // 计算在大圆的周长上可以切出的最多不相交的半径为 smallRadius 的圆的数量
    public static int maxNonOverlappingCircles(double bigRadius, double smallRadius) {
        // 计算大圆的周长
        double circumference = calculateCircumference(bigRadius);

        // 计算小圆的直径
        double smallDiameter = 2 * smallRadius;

        // 计算最多可以切出的小圆数量
        int maxCircles = (int) (circumference / smallDiameter);

        return maxCircles;
    }

    public static JSONArray toRound(double centerLon, double centerLat, double round, double isRound) {
        // 计算小圆的个数
//        int numCircles = (int) (round / isRound);

        int num = maxNonOverlappingCircles(round, isRound);

        JSONArray ployDataList = new JSONArray();

        // 计算每个小圆的中心点坐标
        for (int i = 0; i < num; i++) {
            double angle = 2 * Math.PI * i / num;
            JSONObject jsonObject = calculateCircleCenter(centerLat, centerLon, round, angle, isRound);
            ployDataList.add(jsonObject);
        }

        return ployDataList;
    }

    public String getPoint(String url, String id, String imageUrl, String baseUrl, JSONArray array) {
        BufferedReader br = null;
        BufferedReader brError;
        String line = null;
        try {
            StringBuffer sb = new StringBuffer();
            List<List> lists = array.toJavaList(List.class);
            for (List list : lists) {
                sb.append(list.get(0) + " " + list.get(1) + "    " + list.get(0) + " " + list.get(1) + "\n");
            }
            FileUtil.mkdir(url + "/file/point/" + id);
            FileUtil.mkdir(url + "/file/tif/" + id);
            FileUtil.writeString(sb.toString(), url + "/file/point/" + id + "/" + "point.txt", "UTF-8");
            ProcessBuilder processBuilder = new ProcessBuilder();
            processBuilder.command(
                    "D:\\pythonProject\\MatchSoftWare\\dist\\main\\main.exe",
                    "--imageSource",
                    url + imageUrl,
                    "--imageVerity",
                    url + baseUrl,
                    "--positionFile",
                    url + "/file/point/" + id + "/" + "point.txt",
                    "--resultFile",
                    url + "/tif/point/" + id + "/res.tif"
            );
            return "/file/point/" + id + "/res.tif";
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static String pointPost = "/point_image";

    public static String getPointPost(String url, String fileUrl, String newImage, String baseImage, String id, JSONArray array, JSONArray arrays) {
        try {
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < array.size(); i++) {
                JSONObject object = array.getJSONObject(i);
                JSONObject objects = arrays.getJSONObject(i);
                if (ObjectUtil.isEmpty(object.getJSONArray("position")) && ObjectUtil.isEmpty(objects.getJSONArray("position"))) {
                    continue;
                } else if (ObjectUtil.isNotEmpty(object.getJSONArray("position")) && ObjectUtil.isEmpty(objects.getJSONArray("position"))) {
                    objects.put("position", object.getJSONArray("position"));
                }  else if (ObjectUtil.isEmpty(object.getJSONArray("position")) && ObjectUtil.isNotEmpty(objects.getJSONArray("position"))) {
                    object.put("position", objects.getJSONArray("position"));
                }
                sb.append(object.getJSONArray("position").get(0) + " " + object.getJSONArray("position").get(1) + "    " + objects.getJSONArray("position").get(0) + " " + objects.getJSONArray("position").get(1) + "\n");
            }
            FileUtil.mkdir(fileUrl + "/file/point/" + id);
            FileUtil.writeString(sb.toString(), fileUrl + "/file/point/" + id + "/" + "point.txt", "UTF-8");
            JSONObject json = new JSONObject();
            json.put("imageSource", fileUrl + newImage);
            json.put("imageVerity", fileUrl + baseImage);
            json.put("positionFile", fileUrl + "/file/point/" + id + "/" + "point.txt");
            json.put("resultFile", fileUrl + "/file/point/" + id + "/" + "res.tif");
            json.put("resultJson", fileUrl + "/file/point/" + id + "/" + "res.txt");
            HttpResponse execute = HttpUtil.createRequest(Method.POST, url + pointPost)
                    .body(json.toJSONString())
                    .execute();
            if (execute.getStatus() == HttpStatus.HTTP_OK) {
                JSONObject object = JSONObject.parseObject(execute.body());
                if (200 == object.getInteger("code")) {
                    return "/file/point/" + id + "/";
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static String processPost = "/process_image";

    public static String getProcessPost(String id, String url, String fileUrl, String imageUrl, String type, Double value, Double number, JSONArray array) {
        try {
            if (!getProcessFile(type, array, value, number, fileUrl)) {
                return null;
            }
            JSONObject json = new JSONObject();
            json.put("image_path", imageUrl);
            json.put("json_input_path", fileUrl + "/" + type + ".json");
            FileUtil.touch(fileUrl + "/" + "res.json");
            json.put("json_output_path", fileUrl + "/" + "res.json");
            HttpResponse execute = HttpUtil
                    .createRequest(Method.POST, url + processPost)
                    .body(json.toJSONString())
                    .execute();
            log.info("栅格请求返回结果：{}", execute.getStatus());
            if (execute.getStatus() == HttpStatus.HTTP_OK) {
                JSONObject object = JSONObject.parseObject(execute.body());
                if (200 == object.getInteger("code")) {
                    return "1";
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static boolean getProcessFile(String type, JSONArray array, Double value, Double number, String fileUrl) {
        JSONObject json = new JSONObject();
        try {
            json.put("type", type);
            if ("rectangle".equals(type) || "skewrectangle".equals(type)) {
                json.put("width", value);
                json.put("length", value);
                JSONArray positions = new JSONArray();
                List<List> list = array.toJavaList(List.class);
                for (List l : list) {
                    List pl = new ArrayList();
                    pl.add(l.get(0));
                    pl.add(l.get(1));
                    pl.add(l.get(2));
                    positions.add(pl);
                }
                json.put("positions", positions);
            }
//            else if ("round".equals(type)) {
//                json.put("radius", value);
//                json.put("num", number);
//                JSONArray positions = new JSONArray();
//                positions.add(array.get(0));
//                positions.add(array.get(1));
//                positions.add(array.get(2));
//                json.put("positions", positions);
//            } else if ("rectangle_round".equals(type)) {
//                json.put("num", number);
//                JSONArray positions = new JSONArray();
//                List<List> list = array.toJavaList(List.class);
//                for (List l : list) {
//                    List pl = new ArrayList();
//                    pl.add(l.get(0));
//                    pl.add(l.get(1));
//                    pl.add(l.get(2));
//                    positions.add(pl);
//                }
//                json.put("positions", positions);
//            }
            else {
                return false;
            }
            FileUtil.writeString(json.toJSONString(), fileUrl + "/" + type + ".json", "UTF-8");
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public static JSONObject getProcessFile(String fileUrl) {
        JSONObject resultJson = new JSONObject();
        JSONArray resultArray = new JSONArray();
        String readUtf8String = FileUtil.readUtf8String(fileUrl);
        JSONObject jsonObject = JSONObject.parseObject(readUtf8String);
        String type = jsonObject.getString("type");
        JSONArray positions = jsonObject.getJSONArray("positions");
        if (CollectionUtil.isNotEmpty(positions)) {
            if ("skewrectangle".equals(type) || "rectangle".equals(type)) {
                for (int i = 0; i < positions.size(); i++) {
                    JSONArray jsonArray = positions.getJSONArray(i);
                    List<JSONArray> jsonArrays = jsonArray.toJavaList(JSONArray.class);
                    for (JSONArray a : jsonArrays) {
                        a.set(0, a.get(0));
                        a.set(1, a.get(1));
                    }
                    resultArray.add(jsonArrays);
                }
            } else if ("round".equals(type) || "rectangle_round".equals(type)) {
                resultJson.put("radius", jsonObject.getDouble("subradius"));
                for (int i = 0; i < positions.size(); i++) {
                    JSONArray list = positions.getJSONArray(i);
                    list.set(0, list.get(0));
                    list.set(1, list.get(1));
                    resultArray.add(list);
                }
            }
        } else {
            return null;
        }
        if ("rectangle_round".equals(type)) {
            type = "round";
        }
        resultJson.put("type", type);
        resultJson.put("positions", resultArray);
        return resultJson;
    }

}
